#include "multigeneregionviswidget.h"

#include "../genosage.h"
#include "../../sagevis.h"
#include "contig.h"
#include "genomeelement.h"
#include "SageVis/VisBaseClasses/visbasecontainer.h"
#include "SageVis/VisBaseClasses/visbasehashcontainer.h"
#include "SageVis/VisBaseClasses/visbaselayout.h"
#include "layoutgenomeelements.h"
#include "../../SageVisGuiElements/lineconnectorelement.h"
#include "generegionviewermenusidebar.h"

MultiGeneRegionVisWidget::MultiGeneRegionVisWidget( QPointer<GenoSage> genoSagePointer, QPointer<SageVis> svp, QGraphicsItem *parent, QString *pathToData ) :
    GenoSageBaseWidget(genoSagePointer, svp, parent)
{    
    //---------SETUP-------------

    //CONTAINERS
    contigContainer = new VisBaseHashContainer( svp, this, this);
    contigLabelContainer = new VisBaseContainer( svp, this, this);
    //genomeLabelContainer = new VisBaseHashContainer( svp, this, this);
    genomeElementContainer = new VisBaseHashContainer( svp, this, this );

    dataContainer = new DataContainer(this);

    //DIMENSIONS OF WIDGET
    if( APP_MODE == STANDALONE_MODE )
    {
        setGeometry( QRect(0.0, 0.0, (float) (QApplication::desktop()->availableGeometry().width()), (float) (QApplication::desktop()->availableGeometry().height()-25.0))  );
    }
    else if( APP_MODE == SAGE_NEXT_MODE )
    {
        setGeometry( QRect(0.0, 0.0, 1000.0, 700.0) );//TO DO:  fix
    }

    //totalNt = 100000.0;
    //ntPerPixel = totalNt / geometry().width();

    ntPerPixel = 75.0;
    ntPerPixelZoomFactor = 1.0;
    totalNt = ntPerPixel*ntPerPixelZoomFactor*geometry().width(); //this will change later

    startContigIdx = 0;
    endContigIdx = 0; //will fill these values once data loaded

    //----INITIALIZE MENU
    menu = new GeneRegionViewerMenuSideBar(this);
    connect( menu, SIGNAL(heightChangeSignal(int)), this, SLOT( changeContigHeight(int)) );
    connect( menu, SIGNAL(zoomChangeSignal(int)), this, SLOT(zoomChangeSlot(int)) );
    connect( menu, SIGNAL(sortByContigLengthLongToShortSignal()), this, SLOT(sortByContigLengthLongToShort()) );
    connect( menu, SIGNAL( sortByContigLengthShortToLongSignal()), this, SLOT(sortByContigLengthShortToLong()) );
    connect( menu, SIGNAL(sortByEntrySignal(QString,QString)), this, SLOT(sortByElementSlot(QString,QString)));

    //----INITIALIZE HIGHLIGHT RECT FOR CLICK AND DRAG NAVIGATION
    highlightRect.setCoords(0,0,0,0);

    //---------FLAGS--------------
    setCursor( Qt::ArrowCursor );//make sure arrow cursor is shown in general
    setFlag( QGraphicsItem::ItemClipsChildrenToShape );//contigs stay in bounds
    setFlag( QGraphicsItem::ItemIsFocusable );//needed for keypress event
    setCacheMode(QGraphicsItem::ItemCoordinateCache);//this call is magic- render to pixmap makes it faster


    //--------DEAL WITH GETTING DATA FILES AND LOADING DATA
    bool haveData = pathToData; //data path may or may not have been included
    //If data path not included- ask user for data
    if( !haveData )
    {
//        //hack
//        if( DISPLAY_MODE == WALL_MODE && RUN_MODE == DEBUG_MODE )
//        {
//            gffFiles.append(QDir::homePath()+"/all_Lactobacillus.gff");
//            fastaFiles.append(QDir::homePath()+"/all_Lactobacillus.faa");
//        }

        if( RUN_MODE == DEBUG_MODE ) //debug mode- use pre-programmed data set
        {
//            qDebug() << "preprogrammed data sets loading..." << endl;
////            gffFile = QDir::homePath()+"/all_Lactobacillus.gff";
////             fastaFile = QDir::homePath()+"/all_Lactobacillus.faa";

//            loadSavedProject(QDir::homePath()+"/genomeViewerTestProject.gsp");

            //no need for this anymore
            //gffFile = "";
            //fastaFile = "";
        }
        else //release mode... get data from user
        {
            //get project data from the user
            qDebug() << "Getting data paths from user" << endl;
            getDataFromUser();
        }
    }

    //Note: these are the only two cases, but must be careful of situations where these don't get 'new-ed'

    //----------LOAD AND PROCESS DATA-----------
    //now that data paths to gff and fasta file have been supplied, begin processing the data

    if( RUN_MODE == DEBUG_MODE )
    {
        //loadSavedProject(QDir::homePath()+"/genomeViewerTestProject.gsp", QDir::homePath()+"/genomeData.db");
        //loadSavedProject(QDir::homePath()+"/genomeViewerTestProject.gsp", QDir::homePath()+"/genomeData.db");
        //loadSavedProject(QDir::homePath()+"/bigDataGenomeViewerTestProject.gsp", QDir::homePath()+"/bigGenomeData.db");
        loadSavedProject(QDir::homePath()+"/excinucleaseProject.gsp", QDir::homePath()+"/bigGenomeData.db");
        //loadSavedProject(QDir::homePath()+"/cytotoxicProject1.gsp", QDir::homePath()+"/cytotoxicData1.db");
    }
    else
        loadData();
}

MultiGeneRegionVisWidget::~MultiGeneRegionVisWidget()
{
    qDebug() << "saving project " << endl;
    saveProject("cytotoxicProject2");
}

//--------------------------------GETTING DATA PATH and LOADING DATA------------------------------

//GET PROJECT INFO FROM THE USER
void MultiGeneRegionVisWidget::getProjectDataFromUser()
{
    //TO DO
}

//GET DATA FROM USER
void MultiGeneRegionVisWidget::getDataFromUser()
{
    getGffFileFromUser();//opens file dialog and returns the path to a signal gff file
    getFastaFileFromUser();//opens file dialog and returns the path to a single fasta file
}

//GET GFF FILE FROM USER
void MultiGeneRegionVisWidget::getGffFileFromUser()
{
    gffFiles.clear();//in case another file has been provided
    bool gffFileNameProvided = false;
    QFileDialog *fileDialog = new QFileDialog;
    while( ! gffFileNameProvided ) //while file name not specified
    {
        gffFiles = fileDialog->getOpenFileNames(0, "Select GFF2 File");//save gff file name provided

        //if no filename provided, or something is wrong with the file- ask user again
        if( gffFiles.size() == 0 || gffFiles[0].size() == 0)//if no files or file name is empty
        {
            gffFileNameProvided = false;
        }
        else //can exit loop
        {
            gffFileNameProvided = true;
        }
    }
    delete fileDialog;

    qDebug() << "user has specified " << gffFiles.size() << " gff files " << endl;


}

//GET FASTA FILE FROM USER
void MultiGeneRegionVisWidget::getFastaFileFromUser()
{
    fastaFiles.clear();//in case another file has been provided
    bool fastaFileNameProvided = false;
    QFileDialog *fileDialog = new QFileDialog;
    while( ! fastaFileNameProvided ) //while file name not specified
    {
        fastaFiles = fileDialog->getOpenFileNames(0, "Select FASTA File (.faa)");

        //if no filename provided, or something is wrong with the file- ask user again
        if( fastaFiles.size() == 0 || fastaFiles[0].size() == 0 )
        {
            fastaFileNameProvided = false;
            //print an error message and explain that file is needed to proceed
        }
        else //can exit loop
        {
            fastaFileNameProvided = true;
        }
    }

    qDebug() << "user has specified " << fastaFiles.size() << " fasta files " << endl;
    delete fileDialog;
}


//LAUNCH DATA UPLOADER THREAD
void MultiGeneRegionVisWidget::loadData()
{
    qDebug() << "Loading data" << endl;
    qDebug() << "Begin transaction" << endl;

    //DATABASE
    if( DATA_TYPE == PROPRIETARY_DATA )
    {
        databaseInterface = new ProprietaryGenomeLocalDatabaseInterface(this);
    }
    else if( DATA_TYPE == PUBMED_DATA )
    {
        databaseInterface = new PubMedGenomeLocalDatabaseInterface(this);
    }
    databaseInterface->beginTransaction();


    //----- UPLOAD GENOME DATA ------
    //  Data uploaded on a separate thread.
    //  Once upload is complete, 'dataUploadCompleteSlot' is called.
    //  Then data can be stored and graphical objects can be created.
    thread = new QThread;
    GenomeDataUploader* dataUploader = new GenomeDataUploader(gffFiles, fastaFiles);
    dataUploader->moveToThread(thread);
    connect(dataUploader, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
    connect(thread, SIGNAL(started()), dataUploader, SLOT(process()));
    connect(dataUploader, SIGNAL(finished()), thread, SLOT(quit()));
    connect(dataUploader, SIGNAL(finished()), dataUploader, SLOT(deleteLater()));
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

    //-------------NEED TO DO THIS FOR SIGNALS AND SLOTS WITH MY CUSTOM CLASSES TO WORK---------
    typedef QList< QPointer < GenomeElementDataPacket> > ListOfGenomeElements;
    qRegisterMetaType< QList< QPointer < GenomeElementDataPacket> > >("ListOfGenomeElements");

    typedef QList< QPointer < ContigDataPacket > > ListOfContigDataPackets;
    qRegisterMetaType< QList< QPointer < ContigDataPacket > > >("ListOfContigDataPackets");

    typedef QPointer<GenomeDatabaseInterface> GenomeDatabase;
    qRegisterMetaType< QPointer<GenomeDatabaseInterface> >("GenomeDatabase");

    typedef QPointer<GenomeElementDataPacket> GenomeElementDP;
    qRegisterMetaType< QPointer<GenomeElementDataPacket> >("GenomeElementDP");

    typedef QPointer<ContigDataPacket>  ContigDP;
    qRegisterMetaType< QPointer<ContigDataPacket> >("ContigDP");

    connect( dataUploader, SIGNAL( dataUploadCompleteSignal( QList< QPointer < GenomeElementDataPacket> >, QList< QPointer < ContigDataPacket > >, int )),
             this, SLOT(dataUploadCompleteSlot( QList< QPointer < GenomeElementDataPacket> >, QList< QPointer < ContigDataPacket > >, int )));

   // connect(dataUploader, SIGNAL(genomeElementToCacheSignal(QPointer<GenomeElementDataPacket>)), this, SLOT(cacheThenCommit(QPointer<GenomeElementDataPacket>)) );
   //connect(dataUploader, SIGNAL(genomeElementToCacheSignal(QPointer<GenomeElementDataPacket>)), this, SLOT(addEltToDBThenDelete(QPointer<GenomeElementDataPacket>)) );

   connect(dataUploader, SIGNAL(contigToCacheSignal(QPointer<ContigDataPacket>)), this, SLOT(addContigToDBThenDelete(QPointer<ContigDataPacket>)) );

   //Note:  TO DO:  Track progress
        //connect(dataUploader, SIGNAL(trackProgress(int)), this, SLOT(updateProgressBar(int)));
        //connect(dataUploader, SIGNAL(createdReformattedFileSignal(QString)), this, SLOT(createdReformattedFileSlot(QString)));
        //connect(dataUploader, SIGNAL(finished()), this, SLOT(createContigsSlot()));
    thread->start();
    //Note- don't delete thread pointer now, because needs to run

      //dataUploader->process();

    //----DONE LAUNCHING DATA UPLOAD THREAD----

}

float MultiGeneRegionVisWidget::getNtPerPixel()
{
    return ntPerPixel*ntPerPixelZoomFactor;
}

float MultiGeneRegionVisWidget::getCenterXPosition()
{
    return centerXPos;
}

void MultiGeneRegionVisWidget::errorString(QString theError)
{
        qDebug() << theError << endl;

        if( theError.contains("Clustering failed") )
        {
            qDebug() << "Couldn't find clustering file " << endl;
            exit(1);
        }
}

void MultiGeneRegionVisWidget::changeContigHeight(int newHeightFactor)
{
    float baseHeight = 5.0;

    float newHeight = baseHeight*(float)newHeightFactor/100.0;

    contigContainer->setHeightOfElements(newHeight);
    contigLabelContainer->setHeightOfElements(newHeight);
    contigContainer->layoutElements();
    contigLabelContainer->layoutElements();
    //genomeLabelContainer->layoutElements();
    update();
}

void MultiGeneRegionVisWidget::zoomChangeSlot(int newNtPerPixelZoomFactor)
{

    ntPerPixelZoomFactor = (float)newNtPerPixelZoomFactor/100.0;

    for(int i = 0; i < contigContainer->getNumElements(); i++)
    {
        Contig* c = dynamic_cast<Contig*> (contigContainer->getElement(i));
        c->zoom(ntPerPixelZoomFactor*ntPerPixel);
        //LayoutGenomeElements* l = dynamic_cast<LayoutGenomeElements*> (c->getLayout());
        //c->setNtPerPixel(ntPerPixel*ntPerPixelZoomFactor);
        //l->setNtPerPixel(ntPerPixel*ntPerPixelZoomFactor);

        //c->zoom()
    }

//    totalNt = ntPerPixel * boundingRect().width();

//    qDebug() << "ZOOM " << endl;
//    //-----LAYOUT GENES in contigs and SETUP HEIGHT AND Y POSITION
//    for(int i = 0; i < contigContainer->getNumElements(); i++)
//    {
//        Contig* c = dynamic_cast<Contig*> (contigContainer->getElement(i));
//        //layout genome elements -- non threaded, because otherwise too many threads
//        LayoutGenomeElements* l = dynamic_cast<LayoutGenomeElements*> (c->getLayout());
//        l->setNtPerPixel(ntPerPixel);
//        //contigs[i]->layoutElements();//NonThreaded();
//        c->layoutElements(); //NonThreaded();
//    }
}

void MultiGeneRegionVisWidget::sortByContigLengthLongToShort()
{
    sortByContigLength(true);
}

void MultiGeneRegionVisWidget::sortByContigLengthShortToLong()
{
    sortByContigLength(false);
}

void MultiGeneRegionVisWidget::sortByContigLength(bool longToShort)
{
    QList< QPointer< ContigDataPacket> > cdps;
    QList< QPointer< GenomeElementDataPacket > > gedps;
    databaseInterface->getSortedByLength( cdps, gedps, longToShort);
    qDebug() << "done" << endl;

   clearAllContainersAndLists();

    qDebug() << gedps.size() << " " << cdps.size() << endl;

    qDebug() << "line connectors " << lineConnectionContainer->getNumElements();

    createAndLayoutSlot(gedps, cdps, 1000);//WHY IS IT 1000?

}

void MultiGeneRegionVisWidget::sortByElementSlot(QString elt)
{
    sortByElementSlot(elt, "ClusterId");
}

void MultiGeneRegionVisWidget::sortByElementSlot( QString elt, QString type )
{
    qDebug() << "sort by elt slot: " << elt << endl;

    QList< QPointer< ContigDataPacket> > cdps;
    QList< QPointer< GenomeElementDataPacket > > gedps;

    if( type.compare("ClusterId") == 0 )
    {

        databaseInterface->getContigsWithCluster(elt, cdps, gedps);//TO DO:  add ability to specify sort here

        qDebug() << "num moved to top: " << cdps.size() << endl;
    }
    else
    {
        elt.remove(">");
        databaseInterface->getStringMatches(elt, cdps, gedps);//TO DO:  add ability to specify sort here
    }

        //move existing contigs to the top
        //create others and move to top
        for(int i = cdps.size()-1 ; i >= 0; i--)
        {
            QString contigId = cdps[i]->getContigId();
            if( contigContainer->containsElement(contigId) )//move to top
            {
                contigContainer->removeAndPrepend(contigId);

                QString textToDisplay = "";
                textToDisplay.append( cdps[i]->getSpecies() ).append(" ").append( cdps[i]->getContigId() );
                contigLabelContainer->removeAndPrepend(textToDisplay);
                qDebug() << "remove and pre-pend: " << contigId << endl;

                //giveColorToElementInContig(0, elt, type);
            }
            else
            {
                Contig* c = new Contig( cdps[i], sageVisPointer, this, contigContainer); //create contig

                contigContainer->prepend( c ); //TO DO:  hash prepend

                SageVisTextLabel* label = new SageVisTextLabel( sageVisPointer, this, this );//label for contig
                label->setGeometry( 0.0, 0.0, 50.0, 20.0 );
                //label->setText( cdps[i]->getContigId() );//label contains contig Id
                QString textToDisplay = "";
                textToDisplay.append( cdps[i]->getSpecies() ).append(" ").append( cdps[i]->getContigId() );
                label->setText( textToDisplay );//label contains contig Id

                //Height-connect labels and contigs
                label->forgeConnection( c, HEIGHT_CONNECTION );
                c->forgeConnection(label, HEIGHT_CONNECTION );

                //Hover-connect labels and contigs
                label->forgeConnection( c, HOVER_CONNECTION );
                c->forgeConnection(label, HOVER_CONNECTION );

                //setup line connection
                label->setLineConnectionType( CENTER_RIGHT_LINE_CONNECTION );
                c->setLineConnectionType( CENTER_LEFT_LINE_CONNECTION );
                lineConnect( label, c );

                contigLabelContainer->prepend( label );

                //loop through the data packet's genes and add these genes to element list and the contig
                for(int j = 0; j < cdps[i]->numOfGenomeElements(); j++ )
                {
                    GenomeElementDataPacket* geDP = cdps[i]->getGenomeElementDataPacket(j);
                    GenomeElement* g = new GenomeElement( geDP, sageVisPointer, this, c ); //NOTE:  I have made the contig the parent of the new genome element

                    connect( g, SIGNAL(signalingHover(bool,QGraphicsSceneHoverEvent*,QString)), this, SLOT(receiveGenomeElementHoverSignal(bool,QGraphicsSceneHoverEvent*,QString)) );
                    connect( g, SIGNAL(signalingColorChange(QColor,QString)), this, SLOT(receiveColorChangeSignal(QColor, QString)) );
                    connect( g, SIGNAL(signalingAlignment(float,bool,QString,QString)), this, SLOT(receiveAlignmentSignal(float,bool,QString,QString)) );
                    connect( g, SIGNAL(signalingCenter(QString)), this, SLOT(receiveCenteredSignal(QString)) );

                    label->forgeConnection(g, HEIGHT_CONNECTION);

                    if(type.compare("ClusterId") == 0 && geDP->getClusterId().compare(elt) == 0 )
                        g->setHighlightColor();
                    else if(geDP->getIdentifierToDisplay().contains(elt) )//type.compare("Product") == 0 &&
                        g->setHighlightColor();

                    c->addGenomeElement(g);

                    connect( g, SIGNAL(showInfoBoxSignal(GenomeElementDataPacket*,GenomeElement*)), this, SLOT(showInfoBoxSlot(GenomeElementDataPacket*,GenomeElement*)) );
                    connect( g, SIGNAL(removeInfoBoxSignal(GenomeElementDataPacket*,GenomeElement*)), this, SLOT(removeInfoBoxSlot(GenomeElementDataPacket*,GenomeElement*)) );
                    connect( g, SIGNAL(moveToTopSignal(QString)), this, SLOT(sortByElementSlot(QString)) );

                    //genomeElements << g; //add genome element to list
                    if( geDP->getHasCluster() )//if element has a cluster, add it to hash table
                    {
                        genomeElementContainer->addElement( g, geDP->getClusterId() );//add genome element to its container- which includes a hashtable so can find genes quickly by clusterId
                    }
                    else
                    {
                        genomeElementContainer->addElement( g );
                    }
                }
            }
        }
//    }//end ClusterId
//    else
//    {
//        qDebug() << "sort by product" << endl;
//        elt.remove(">");
//        QStringList products = databaseInterface->getStringMatches(elt);//TO DO:  add ability to specify sort here
//        for(int i = 0; i < products.size(); i++)
//        {
//            qDebug() << "   " << products[i] << endl;
//        }
//        return;
//    }

    //launch the organizer and layout thread
    launchLayoutThread();

    qDebug() << "connect elements with same key! " << endl;
    //connect all genome elements by cluster id
    //turning this off to try to boost performace- will connect on the fly
//    genomeElementContainer->connectElementsWithSameKey(HOVER_CONNECTION);
//    genomeElementContainer->connectElementsWithSameKey(COLOR_CONNECTION);
//    genomeElementContainer->connectElementsWithSameKey(ALIGNMENT_CONNECTION);
//    genomeElementContainer->connectElementsWithSameKey(CENTER_CONNECTION);
    qDebug() << "done connect elements with same key! " << endl;

    giveColorToElementInContig(0, elt, type);
    //hover connect genes with the same cluster
    update();

    saveProject( QDir::homePath() + "/" + elt + QString("Project.gsp") );

}

void MultiGeneRegionVisWidget::giveColorToElementInContig(int contigIdx, QString elt, QString field)
{
    if( contigIdx >= contigContainer->getNumElements() || contigIdx < 0  )
        return;

    Contig* c = dynamic_cast<Contig*> (contigContainer->getElement(contigIdx));
    for(int i = 0; i < c->getNumElements(); i++)
    {
        GenomeElement* g = dynamic_cast<GenomeElement*> (c->getElement(i));
        if(field.compare("ClusterId") == 0 && g->getClusterId().compare(elt) == 0 )
            g->setColor( QColor(255, 157, 62) ); //setHighlightColor();
        if(field.compare("Product") == 0 && g->getIdentifierToDisplay().compare(elt) == 0 )
            g->setColor( QColor(255, 157, 62) ); //g->setHighlightColor();

    }
}

void MultiGeneRegionVisWidget::receiveGenomeElementHoverSignal(bool hovering, QGraphicsSceneHoverEvent* event,  QString key)
{
    qDebug() << "processing hover signal from genome element " << endl;
    QList< QPointer<VisBaseElement> > elts = genomeElementContainer->getElements(key);
    for(int i = 0 ; i < elts.size(); i++ )
    {
        GenomeElement* g = dynamic_cast<GenomeElement*> ( elts[i].data() );
        //if( g->getClusterId().compare( key ) != 0 )
            g->processHoverEvent(event);
    }
    qDebug() << "done" << endl;
}

void MultiGeneRegionVisWidget::receiveColorChangeSignal(QColor color, QString key)
{
    qDebug() << "processing color change signal from genome element " << endl;
    QList< QPointer<VisBaseElement> > elts = genomeElementContainer->getElements(key);
    for(int i = 0 ; i < elts.size(); i++ )
    {
        GenomeElement* g = dynamic_cast<GenomeElement*> ( elts[i].data() );
        //if( g->getClusterId().compare( key ) != 0 )
            g->processColorChangeEvent(color);
    }
    qDebug() << "done" << endl;
}

void MultiGeneRegionVisWidget::receiveCenteredSignal(QString key)
{
    qDebug() << "processing color change signal from genome element " << endl;
    QList< QPointer<VisBaseElement> > elts = genomeElementContainer->getElements(key);
    for(int i = 0 ; i < elts.size(); i++ )
    {
        GenomeElement* g = dynamic_cast<GenomeElement*> ( elts[i].data() );
        //if( g->getClusterId().compare( key ) != 0 )
            g->centerSlot();
    }
    qDebug() << "done" << endl;
}

void MultiGeneRegionVisWidget::receiveAlignmentSignal(float xPos, bool posStrand, QString parentContigId, QString key)
{
    qDebug() << "processing alignment signal from genome element " << endl;
    QList< QPointer<VisBaseElement> > elts = genomeElementContainer->getElements(key);
    for(int i = 0 ; i < elts.size(); i++ )
    {
        GenomeElement* g = dynamic_cast<GenomeElement*> ( elts[i].data() );
        //if( g->getClusterId().compare( key ) != 0 )
            g->alignmentSlot(xPos, posStrand, parentContigId);
    }
    qDebug() << "done" << endl;
}

void MultiGeneRegionVisWidget::clearAllContainersAndLists()
{

    //clear my containers
    contigLabelContainer->clearAndDelete();
    contigContainer->clearAndDelete();
    genomeElementContainer->clearAndDelete();
    lineConnectionContainer->clearAndDelete();


    //empty data packets
    dataContainer->clearAndDelete();


}

void MultiGeneRegionVisWidget::connectGenomeElements(QString key)
{
    genomeElementContainer->connectElementsWithSameKey(HOVER_CONNECTION, key);
    genomeElementContainer->connectElementsWithSameKey(COLOR_CONNECTION, key);
    genomeElementContainer->connectElementsWithSameKey(ALIGNMENT_CONNECTION, key);
    genomeElementContainer->connectElementsWithSameKey(CENTER_CONNECTION, key);
}

void MultiGeneRegionVisWidget::showInfoBoxSlot(GenomeElementDataPacket * dataPacket, GenomeElement *genomeElement )
{
//    infoBox = InfoBox(sageVisPointer, this, this);
//    infoBox->setPos( mapFromItem( genomeElement, 0.0, 0.0 ) );
//    infoBox->setZValue(100.0);
//    infoBox->forgeConnection(genomeElement, HOVER_CONNECTION); //so that genomeElement remains highlighted
//    infoBox->forgeConnection(dynamic_cast<Contig*> (genomeElement->parent()), HOVER_CONNECTION );
//    genomeElement->forgeConnection(infoBox, XPOS_CONNECTION); //so that when genomeElement moves, so does the infobox
//                        //TO DO:  make this not just xpos connected but move x connected- just move by deltaX, not taking xvalue directly.
}


void MultiGeneRegionVisWidget::removeInfoBoxSlot(GenomeElementDataPacket * dataPacket, GenomeElement *genomeElement )
{
//    if( infoBox != NULL )
//        delete infoBox;
}

//COLLECT RESULTS FROM DATA UPLOADER and LAUNCH CONTIG AND GENOME ELEMENT CREATION and LAYOUTer
//slot called when genome data uploader thread is done
//returns a set of genome data elements, contigs and a pointer to the database interface for these data
void MultiGeneRegionVisWidget::dataUploadCompleteSlot( QList< QPointer < GenomeElementDataPacket> > geDataPackets, QList< QPointer < ContigDataPacket > > cDataPackets, int contigCount )
{
    qDebug() << "data upload complete " << endl;

    //DB STUFF
    //......
    //committing elements...
    databaseInterface->commitTransaction();
    qDebug() << "addedCount = " << addedCount << endl;
    qDebug() << "additional elts: " << geDataPackets.size() << endl;

    //databaseInterface->batchAdd( geDataPackets );//batch add all these elements

    databaseInterface->batchAdd( cDataPackets );//batch add all these elements

    //ADD TO DATABASE- separate thread
    //count how many to add, how many to delete
//    int lim = 1000;
//    if( lim > cDataPackets.size() )
//        lim = cDataPackets.size();
//    int genomeElementCount = 0;
//    for(int i =0; i < lim; i++)
//    {
//        genomeElementCount += cDataPackets[i]->numOfGenomeElements();
//    }
//    qDebug() << genomeElementCount << endl;
    //databaseInterface->addGenomeElementsThenDelete(geDataPackets, genomeElementCount);


    //THEN CREATE CONTIGS AND LAYOUT
    createAndLayoutSlot(geDataPackets, cDataPackets, contigCount);
}

void MultiGeneRegionVisWidget::createAndLayoutSlot( QList< QPointer < GenomeElementDataPacket> > geDataPackets, QList< QPointer < ContigDataPacket > > cDataPackets, int contigCount )
{
//    genomeElementDataPackets.append(geDataPackets); //append this list to the main lis
//    contigDataPackets.append( cDataPackets );//append this list to the main list

    dataContainer->appendGenomeElements( geDataPackets );
    dataContainer->appendContigs( cDataPackets );

    //NOTE - later if multiple genome data upload threads are launched, you may need to wait for this to be called a number of times before proceeding
    //instantiate the graphical objects
    createGenomeElementsAndContigs();

    //launch the organizer and layout thread
    launchLayoutThread();

    qDebug() << "connect elements with same key! " << endl;
    //connect all genome elements by cluster id
    //removed to try to do it on the fly
//    genomeElementContainer->connectElementsWithSameKey(HOVER_CONNECTION);
//    genomeElementContainer->connectElementsWithSameKey(COLOR_CONNECTION);
//    genomeElementContainer->connectElementsWithSameKey(ALIGNMENT_CONNECTION);
//    genomeElementContainer->connectElementsWithSameKey(CENTER_CONNECTION);
    qDebug() << "done connect elements with same key! " << endl;


    //hover connect genes with the same cluster
    update();
}

void MultiGeneRegionVisWidget::addEltToDBThenDelete( QPointer< GenomeElementDataPacket > genomeElementDataPacket )
{
    if( addedCount % 1000 == 0 )
        qDebug() << "Add elt to db slot " << addedCount << endl;
    databaseInterface->addGenomeElementThenDeleteIt(genomeElementDataPacket);
//    mutex.lock();
//    doneAddingToDb.wait(&mutex);
    addedCount++;
//    delete genomeElementDataPacket;
//    doneAddingToDb.wakeAll();
//    mutex.unlock();
}

void MultiGeneRegionVisWidget::addContigToDBThenDelete(QPointer<ContigDataPacket> contigDataPacket)
{
//    int numElts = contigDataPacket->numOfGenomeElements();
//    for(int i = 0 ; i < numElts; i++ )
//    {
//        addEltToDBThenDelete( contigDataPacket->getGenomeElementDataPacket(i) );
//    }
    addedCount += contigDataPacket->numOfGenomeElements();
    databaseInterface->addContigThenDeleteIt(contigDataPacket);
}


void MultiGeneRegionVisWidget::cacheThenCommit( QPointer< GenomeElementDataPacket > genomeElementDataPacket )
{
    genomeElementDataPacketCache.append(genomeElementDataPacket);//cache
    addedCount++;
    if( addedCount > 1000 )//1000 )//if big enough
    {
        qDebug() << "cache committed" << endl;
        commitCache();//commit
        addedCount = 0;
    }

}

void MultiGeneRegionVisWidget::commitCache()
{
    databaseInterface->batchAddThenDelete(genomeElementDataPacketCache);//commit

}

//CREATE GRAPHICAL CONTIGS AND GENOME ELEMENTS
//instantiate the genome elements, contigs, and labels
void MultiGeneRegionVisWidget::createGenomeElementsAndContigs()
{

    qDebug() << "Num Contigs: " << dataContainer->getNumContigs() << " Num Genome Elements " << dataContainer->getNumGenomeElements() << endl;

    //for all contigs
    for(int i = 0; i < 1000 && i < dataContainer->getNumContigs() ; i++)//contigDataPackets.size(); i++)
    {
        Contig* c = new Contig( dataContainer->getContigDataPacket(i), sageVisPointer, this, contigContainer); //create contig

        SageVisTextLabel* label = new SageVisTextLabel( sageVisPointer, this, this );//label for contig
        label->setGeometry( 0.0, 0.0, 50.0, 20.0 );
        QString textToDisplay = "";
        textToDisplay.append( dataContainer->getContigDataPacket(i)->getSpecies() ).append(" ").append( dataContainer->getContigDataPacket(i)->getContigId() );
        label->setText( textToDisplay );//label contains contig Id
        //label->setUniqueId(
//        //genome label
        //Height-connect labels and contigs
        label->forgeConnection( c, HEIGHT_CONNECTION );
        c->forgeConnection(label, HEIGHT_CONNECTION );

        //Hover-connect labels and contigs
        label->forgeConnection( c, HOVER_CONNECTION );
        c->forgeConnection(label, HOVER_CONNECTION );

        //setup line connection
        label->setLineConnectionType( CENTER_RIGHT_LINE_CONNECTION );
        c->setLineConnectionType( CENTER_LEFT_LINE_CONNECTION );
        lineConnect( label, c );

        //loop through the data packet's genes and add these genes to element list and the contig
        for(int j = 0; j < dataContainer->getContigDataPacket(i)->numOfGenomeElements(); j++ )
        {
            GenomeElementDataPacket* geDP = dataContainer->getContigDataPacket(i)->getGenomeElementDataPacket(j);
            GenomeElement* g = new GenomeElement( geDP, sageVisPointer, this, c ); //NOTE:  I have made the contig the parent of the new genome element
            connect( g, SIGNAL(signalingHover(bool,QGraphicsSceneHoverEvent*,QString)), this, SLOT(receiveGenomeElementHoverSignal(bool,QGraphicsSceneHoverEvent*,QString)) );
            connect( g, SIGNAL(signalingColorChange(QColor,QString)), this, SLOT(receiveColorChangeSignal(QColor, QString)) );
            connect( g, SIGNAL(signalingAlignment(float,bool,QString,QString)), this, SLOT(receiveAlignmentSignal(float,bool,QString,QString)) );
            connect( g, SIGNAL(signalingCenter(QString)), this, SLOT(receiveCenteredSignal(QString)) );

            c->addGenomeElement(g);

            connect( g, SIGNAL(showInfoBoxSignal(GenomeElementDataPacket*,GenomeElement*)), this, SLOT(showInfoBoxSlot(GenomeElementDataPacket*,GenomeElement*)) );
            connect( g, SIGNAL(removeInfoBoxSignal(GenomeElementDataPacket*,GenomeElement*)), this, SLOT(removeInfoBoxSlot(GenomeElementDataPacket*,GenomeElement*)) );
            connect( g, SIGNAL(moveToTopSignal(QString)), this, SLOT(sortByElementSlot(QString)) );

            label->forgeConnection(g, HEIGHT_CONNECTION);

            //genomeElements << g; //add genome element to list
            if( geDP->getHasCluster() )//if element has a cluster, add it to hash table
            {
                genomeElementContainer->addElement( g, geDP->getClusterId() );//add genome element to its container- which includes a hashtable so can find genes quickly by clusterId
            }
            else
            {
                genomeElementContainer->addElement( g );
            }
        }

        //contigs << c; //add contig to list
        contigContainer->addElement( c , c->getContigId() );

        //contigLabels << label;//add label to list
        contigLabelContainer->addElement( label );
    }
}

void MultiGeneRegionVisWidget::launchLayoutThread()
{
    //------LAYOUT CONTIGS AND CONTIG LABELS------
    int startHeight = 5;

    //----SET HEIGHT OF CONTIGS AND CONTIG LABELS
    //       Contigs and contig labels start at same height
        //shouldn't need to call for both, since height connected
    contigLabelContainer->setHeightOfElements( startHeight );
    //contigContainer->setHeightOfElements( 10 );//don't need, because of connection

    //removed genome label layout

    //----LAYOUT CONTIG LABELS
    //  -----SET CONTIG LABEL X POS:  NEXT TO MENU
    float contigLabelXPos = menu->boundingRect().width() + menu->pos().x() + 20.0; //+ 200.0;// I made 100 the assumed genomeLabel width...  + genomeLabelContainer->getMaxElementWidth();
    contigLabelContainer->setXPosOfElements( contigLabelXPos );

    //   ----LAYOUT CONTIG LABELS VERTICALLY
    VerticalStackLayout* layout2 = new VerticalStackLayout;
    //layout2->setElementsCentered(true);//still determining if needs to be centered or not for correct alignment
    contigLabelContainer->setLayout( layout2 );
    contigLabelContainer->layoutElementsNonThreaded();//I changed this to non-threaded so that I could det contigs on screen
            //runs fine threaded
        //layout pointer will get deleted by container


    //-----LAYOUT CONTIGS
    // -------SET X POS OF CONTIGS
    float shiftX = contigLabelContainer->getMaxElementWidth() + 10.0 + contigLabelXPos;//move contigs over to be 10 px away from longest label
    contigContainer->setXPosOfElements( 2 );//set initial x position
    contigContainer->setWidthOfElements( (float) boundingRect().width()-shiftX );//set initial width
    contigContainer->setGeometry(shiftX, 0.0, boundingRect().width()-shiftX, boundingRect().height());//doing this because it is the parent of the contigs
    contigContainer->setFlag(QGraphicsItem::ItemClipsChildrenToShape);

    //store center x position
    centerXPos = boundingRect().x() +  (boundingRect().width() - shiftX)/2.0 + shiftX;
    qDebug () << "CENTER X POS = " << centerXPos << " x: " << boundingRect().x() << " w = " << boundingRect().width() << "shiftX " << shiftX << endl;

    //--------LAYOUT CONTIGS VERTICALLY
    VerticalStackLayout* layout = new VerticalStackLayout;//apply layout
    contigContainer->setLayout(layout);
    contigContainer->layoutElementsNonThreaded();//I changed this to non-threaded so that I could det contigs on screen
                                                    //runs fine threaded
        //layout pointer will get deleted by container

    //ntPerPixel  = totalNt/(boundingRect().width()-shiftX);
    totalNt = ntPerPixel*ntPerPixelZoomFactor*(boundingRect().width()-shiftX);

    //-----LAYOUT GENES in contigs and SETUP HEIGHT AND Y POSITION
    for(int i = 0; i < contigContainer->getNumElements(); i++)
    {
        //set height of genome elements
        Contig* c = dynamic_cast<Contig*> (contigContainer->getElement(i) ) ;
        c->setHeightOfElements( startHeight );
        c->connectTwoWayElementsToContainer(HEIGHT_CONNECTION);

        //layout genome elements -- non threaded, because otherwise too many threads
        LayoutGenomeElements* l = new LayoutGenomeElements;
        l->setStartNt(0);
        l->setStartX(0);
        l->setNtPerPixel(ntPerPixel*ntPerPixelZoomFactor);

        c->setNtPerPixel(ntPerPixel*ntPerPixelZoomFactor);

        float xLen = (float)c->getContigLength()/(float)(ntPerPixel*ntPerPixelZoomFactor);
        float stopX = xLen;
        //if( xLen > c->geometry().width() )
        //    stopX = c->geometry().width();
        l->setStopX( stopX );

        float ntLen = (float)c->getContigLength();
        //if( ntLen > totalNt )
        //    ntLen = totalNt;
        l->setStopNt(ntLen);//totalNt);//100000);

        c->setLayout(l);
        c->layoutElements();//NonThreaded();
    }

    for(int i = 0; i < lineConnectionContainer->getNumElements(); i++)//lineConnections.size(); i++)
    {
        //lineConnections[i]->update();
        lineConnectionContainer->getElement(i)->update();
    }

    //remove this, once project successfully saved
    //saveProject(QDir::homePath() + "/genomeViewerTestProject.gsp");


    //qDebug() << "line connector count " << lineConnections.size() << endl;


    //---HANDLE CONTIGS ON SCREEN AND GENOME LABELS
    determineContigsOnScreen();
    //createGenomeLabelsForContigsOnScreen();//no longer using
}

void MultiGeneRegionVisWidget::determineContigsOnScreen()
{
    bool startFound = false;
    bool endFound = false;
    //bool done = false;
    for(int i = 0; i < contigContainer->getNumElements(); i++ ) //&& !done; i++)
    {
        Contig* c = dynamic_cast<Contig*> (contigContainer->getElement(i) ) ;
        float y = c->pos().y();
        if( y >= boundingRect().y() && !startFound )
        {
            startContigIdx = i;
            startFound = true;
        }
        if( y > boundingRect().y()+boundingRect().height() && !endFound )
        {
            endContigIdx = i-1;
            endFound = true;
            if( endContigIdx < 0 )
                endContigIdx = 0;
            //done = true;
        }
        //if( i == contigContainer.getNumElements()-1 )
        //    done = true;

    }

    if( !endFound )
        endContigIdx = contigContainer->getNumElements()-1;

    qDebug() << "start idx: " << startContigIdx << " end idx: " << endContigIdx << endl;
}

void MultiGeneRegionVisWidget::createGenomeLabelsForContigsOnScreen()
{
//    genomeLabelContainer->clear(); //empty genomeLabelContainer
//    qDebug() << "emptied container " << endl;

//    for(int i = startContigIdx; i < endContigIdx; i++)
//    {
//        //retrieve contig
//        Contig* c = dynamic_cast<Contig*> ( contigContainer->getElement(i) );

//        //retrieve contiglabel
//        SageVisTextLabel* label = dynamic_cast<SageVisTextLabel*> (contigLabelContainer->getElement(i) );

//        //make genome label- check to see if it already exists
//        SageVisTextLabel* genomeLabel;
//        if( genomeLabelContainer->containsElement( dataContainer->getContigDataPacket(i)->getSpecies() ) )
//        {
//            qDebug() << "contains element " << endl;
//            QString key = dataContainer->getContigDataPacket(i)->getSpecies();
//            qDebug() << "key = " << key;
//            VisBaseElement* vbe = genomeLabelContainer->getElements( key ).at(0).data();
//            genomeLabel = dynamic_cast<SageVisTextLabel*> (vbe);
//        }
//        else
//        {
//            genomeLabel = new SageVisTextLabel( sageVisPointer, this, this);
//            genomeLabel->setGeometry(0.0, 0.0, 50.0, 20.0);
//            genomeLabel->setText( dataContainer->getContigDataPacket(i)->getSpecies() );
//            genomeLabel->setLineConnectionType(CENTER_RIGHT_LINE_CONNECTION);
//            genomeLabelContainer->addElement(genomeLabel, dataContainer->getContigDataPacket(i)->getSpecies() );
//        }

//        lineConnect(label, genomeLabel, CENTER_LEFT_LINE_CONNECTION, CENTER_RIGHT_LINE_CONNECTION);

//        genomeLabel->forgeConnection(label, HOVER_CONNECTION);
//        label->forgeConnection( genomeLabel, HOVER_CONNECTION);

//        genomeLabel->forgeConnection(label, HEIGHT_CONNECTION);
//        label->forgeConnection( genomeLabel, HEIGHT_CONNECTION);

//        //shuldn't have to do this... but connections are not transitive
//        genomeLabel->forgeConnection(c, HOVER_CONNECTION);
//        c->forgeConnection( genomeLabel, HOVER_CONNECTION);

//        genomeLabel->forgeConnection(c, HEIGHT_CONNECTION);
//        c->forgeConnection( genomeLabel, HEIGHT_CONNECTION);
//    }

//    genomeLabelContainer->setHeightOfElements(5); //i copied this height from above

//    //---LAYOUT GENOME LABELS
//        float genomeLabelXPos = menu->boundingRect().width() + menu->pos().x() + 20.0;
//        genomeLabelContainer->setXPosOfElements(genomeLabelXPos);

//        VerticalStackLayout* layout3 = new VerticalStackLayout;
//        genomeLabelContainer->setLayout(layout3);
//        genomeLabelContainer->layoutElements();

//    qDebug() << "GENOME LABEL COUNT " << genomeLabelContainer->getNumElements() << endl;


    //note: i had to hard code in an assumed width for the genome label..


}

void MultiGeneRegionVisWidget::saveProject(QString filename)
{
    QFile out( filename );
    if( ! out.open( QIODevice::WriteOnly) )//
    {
        qDebug() << "failed to open output file " << endl;
        return;
    }

    //write project info to file
    QTextStream outStream(&out);

    outStream << "Date type:    PUBMED_DATA" <<  endl;

    //write data to file
//    for(int i = 0; i < dataContainer->getNumContigs(); i++)
//        outStream << dataContainer->getContigDataPacket(i)->printOutContigData();

    for(int i =0 ; i < contigContainer->getNumElements() && i < 500; i++)
    {
        Contig* c = dynamic_cast<Contig*> (contigContainer->getElement(i));
        outStream << c->printOutContigData() ;
    }

    out.close();
}

void MultiGeneRegionVisWidget::loadSavedProject(QString filename, QString dbName)
{
    qDebug() << "uploading: " << filename << endl;
    GenomeProjectUploader* uploader = new GenomeProjectUploader(filename, this);

    //DATABASE
    if( DATA_TYPE == PROPRIETARY_DATA )
    {
       // databaseInterface = new ProprietaryGenomeLocalDatabaseInterface(dbName, this);
        //TO DO
    }
    else if( DATA_TYPE == PUBMED_DATA )
    {
        databaseInterface = new PubMedGenomeLocalDatabaseInterface(dbName, this);
    }

    //-------------NEED TO DO THIS FOR SIGNALS AND SLOTS WITH MY CUSTOM CLASSES TO WORK---------
    typedef QList< QPointer < GenomeElementDataPacket> > ListOfGenomeElements;
    qRegisterMetaType< QList< QPointer < GenomeElementDataPacket> > >("ListOfGenomeElements");

    typedef QList< QPointer < ContigDataPacket > > ListOfContigDataPackets;
    qRegisterMetaType< QList< QPointer < ContigDataPacket > > >("ListOfContigDataPackets");

    typedef QPointer<GenomeDatabaseInterface> GenomeDatabase;
    qRegisterMetaType< QPointer<GenomeDatabaseInterface> >("GenomeDatabase");

    connect( uploader, SIGNAL( dataUploadCompleteSignal( QList< QPointer < GenomeElementDataPacket> >, QList< QPointer < ContigDataPacket > >, int )),
             this, SLOT(createAndLayoutSlot( QList< QPointer < GenomeElementDataPacket> >, QList< QPointer < ContigDataPacket > >, int )));
    //Note:  TO DO:  Track progress
        //connect(dataUploader, SIGNAL(trackProgress(int)), this, SLOT(updateProgressBar(int)));
        //connect(dataUploader, SIGNAL(createdReformattedFileSignal(QString)), this, SLOT(createdReformattedFileSlot(QString)));
        //connect(dataUploader, SIGNAL(finished()), this, SLOT(createContigsSlot()));

    uploader->readData();

}

//------------------INTERACTIVITY--------------------------------------
//on mouse press, user is initializing a 'click and drag navigation event'
// set 'clickAndDragInitialized' to be true, and set up the mousePressStartPoint as well as deltaY
// so that the click and drag event can be processed
void MultiGeneRegionVisWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    qDebug() << "mouse press " << event->pos().x() << " " << event->pos().y()  ;

    //determineContigsOnScreen();

    mousePressStartPt = event->pos();
    clickAndDragInitialized = true;
    deltaY = 0.0;
    deltaX = 0.0;
    prevX = event->pos().x();

    highlightRect.setCoords( boundingRect().x(), boundingRect().y(), boundingRect().x()+boundingRect().width(), boundingRect().y()+boundingRect().height() );

    setFocus();//not sure why i am using this ... was in previous version


//    //TESTING
//    sortByElementSlot("Cluster4", "Cluster");
//    sortByElementSlot("Cluster17", "Cluster");
//    sortByElementSlot("Cluster530", "Cluster");
}

//on mouse move event
//  if user has initialized a navigation event (click and drag)
//  then compute how much to move in the contigs on screen
void MultiGeneRegionVisWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    if( !clickAndDragInitialized )
        return;

    qDebug() << "mouse move!!" << endl;

    QPointF currPt = event->pos();
    deltaY = currPt.y() - mousePressStartPt.y();
    deltaX = currPt.x() - prevX;// mousePressStartPt.x();//prevX;//mousePressStartPt.x();
    prevX = currPt.x();

    //---MOVE CONTIGS
    VerticalStackLayout* l = dynamic_cast<VerticalStackLayout*> (contigContainer->getLayout());
    l->setStartYPos(boundingRect().y() + deltaY);
    contigContainer->layoutElementsNonThreaded();

    //---MOVE CONTIG LABELS
    l = dynamic_cast<VerticalStackLayout*> (contigLabelContainer->getLayout());
    l->setStartYPos(boundingRect().y() + deltaY);
    contigLabelContainer->layoutElementsNonThreaded();

    highlightRect.setCoords( boundingRect().x(), boundingRect().y()+deltaY, boundingRect().x()+boundingRect().width(), boundingRect().y()+boundingRect().height()+deltaY );

    //---COMPUTE
    float deltaNt = -1.0* (ntPerPixel*ntPerPixelZoomFactor*deltaX);
    //-----LAYOUT GENES in contigs and SETUP HEIGHT AND Y POSITION
    for(int i = 0; i < contigContainer->getNumElements(); i++)
    {
        //layout genome elements -- non threaded, because otherwise too many threads
        Contig* c = dynamic_cast<Contig*> (contigContainer->getElement(i));
        LayoutGenomeElements* l = dynamic_cast<LayoutGenomeElements*> (c->getLayout());

        //c->moveBy(deltaX, deltaNt );
        c->moveBy(deltaX);
        c->layoutElementsNonThreaded();
    }


    qDebug() << "mouse move " << deltaX <<" " << deltaY << endl;



}

//on mouse release event
//  end the click and drag event
//  and reset values so that elements can be displayed
void MultiGeneRegionVisWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    qDebug() << "mouse release  " << event->pos().x() << " " << event->pos().y()  ;

    if( !clickAndDragInitialized )
        return;

    clickAndDragInitialized = false;

    QPointF currPt = event->pos();
    deltaX = currPt.x() - prevX;// mousePressStartPt.x();//prevX;//mousePressStartPt.x();

    if( contigContainer->getElement(0)->pos().y() > boundingRect().y()-50.0 )
    {
//        //---MOVE CONTIGS
        VerticalStackLayout* l = dynamic_cast<VerticalStackLayout*> (contigContainer->getLayout());
        l->setStartYPos(boundingRect().y());
        l->setStartEltIdx(0);
        contigContainer->layoutElementsNonThreaded();

        //---MOVE CONTIG LABELS
        l = dynamic_cast<VerticalStackLayout*> (contigLabelContainer->getLayout());
        l->setStartYPos(boundingRect().y());
        l->setStartEltIdx(0);
        contigLabelContainer->layoutElementsNonThreaded();
    }
    else if( contigContainer->getElement( contigContainer->getNumElements()-1 )->pos().y() < boundingRect().y() + boundingRect().height())
    {
        //TO DO
//        //---MOVE CONTIGS
//        VerticalStackLayout* l = dynamic_cast<VerticalStackLayout*> (contigContainer->getLayout());
//        l->setStartYPos(boundingRect().y());
//        contigContainer->layoutElementsNonThreaded();

//        //---MOVE CONTIG LABELS
//        l = dynamic_cast<VerticalStackLayout*> (contigLabelContainer->getLayout());
//        l->setStartYPos(boundingRect().y());
//        contigLabelContainer->layoutElementsNonThreaded();
    }
    else
    {
        //---MOVE CONTIGS
        VerticalStackLayout* l = dynamic_cast<VerticalStackLayout*> (contigContainer->getLayout());
        //l->setStartYPos(boundingRect().y());
        l->resetStartEltIdx();
        contigContainer->layoutElementsNonThreaded();

        //---MOVE CONTIG LABELS
        l = dynamic_cast<VerticalStackLayout*> (contigLabelContainer->getLayout());
        l->resetStartEltIdx();
        //l->setStartYPos(boundingRect().y());
        contigLabelContainer->layoutElementsNonThreaded();
    }

    highlightRect.setCoords( 0, 0, 0, 0 );

    //-----LAYOUT GENES in contigs and SETUP HEIGHT AND Y POSITION
    for(int i = 0; i < contigContainer->getNumElements(); i++)
    {
        //layout genome elements -- non threaded, because otherwise too many threads
        Contig* c = dynamic_cast<Contig*> (contigContainer->getElement(i));
        LayoutGenomeElements* l = dynamic_cast<LayoutGenomeElements*> (c->getLayout());
//        l->resetIfOutOfBounds();
//        c->setDeltaX(deltaX);//event->pos().x() - mousePressStartPt.x() ); //setContigStartX( event->pos().x() - mousePressStartPt.x()  );
//        qDebug() << "mouse release setting delta x" << endl;

        //c->moveBy();



        //c->layoutElementsNonThreaded();
    }

    //sortByContigLength(true);

    determineContigsOnScreen();
    createGenomeLabelsForContigsOnScreen();

}



//-----------------SIZE AND SHAPE FUNCTIONS----------------------------

void MultiGeneRegionVisWidget::setGeometry(const QRectF &geom)
{
    prepareGeometryChange();
    QGraphicsWidget::setGeometry(geom);
    setPos(geom.topLeft());
}

void MultiGeneRegionVisWidget::setGeometry(qreal x, qreal y, qreal w, qreal h)
{
    setGeometry(QRect(x, y, w, h));
}

QRectF MultiGeneRegionVisWidget::boundingRect() const
{
    return QRectF(QPointF(0,0), geometry().size());
}


QPainterPath MultiGeneRegionVisWidget::shape() const
{
    QPainterPath path;
    path.addRect(boundingRect());
    return path;
}


//QSizeF MultiGeneRegionVisWidget::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
//{
//    switch (which) {
//    case Qt::MinimumSize:
//        return QSizeF(1000, 600);
//    case Qt::PreferredSize:
//        return QSizeF(1200, 700);
//    case Qt::MaximumSize:
//        return QSizeF(1400, 800);
//    default:
//        break;
//    }
//    return constraint;
//}



//----------------------------DRAW FUNCTIONS---------------------------------
void MultiGeneRegionVisWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    //----prevent compiler warnings by declaring what I am not using---
    Q_UNUSED(widget);
    Q_UNUSED(option);

    //---set color---
    QColor backgroundColor;
    backgroundColor.setRgb(20.0, 20.0, 20.0);
    //if( hovering )
    //    backgroundColor.setRgb(90.0, 90.0, 90.0);

    //---paint background rect---
    painter->setBrush(backgroundColor);
    painter->setPen( Qt::NoPen );
    painter->drawRoundedRect(boundingRect(), 10.0, 10.0);

    //TO DO:  make sure this works
    QColor highlightColor( backgroundColor.red()+10.0, backgroundColor.green()+10.0, backgroundColor.blue()+10.0);
    painter->setBrush( highlightColor );
    painter->setPen( Qt::NoPen );
    painter->drawRoundedRect(highlightRect, 10.0, 10.0);
}


/*
  Scratch:

  SETTING UP A SCROLL AREA AND LINEAR LAYOUT
  Layout worked, scroll area did not
  Abandoned because wanted a dynamic layout
    //--------INITALIZE VARIABLES-------
    contigScrollArea = new QScrollArea;

    contigScrollAreaProxy = new QGraphicsProxyWidget(this);
    contigScrollAreaProxy->setWidget( contigScrollArea );
    contigScrollAreaProxy->setPos(0, 0);
    //contigScrollAreaProxy->setGeometry(QRectF(0, 0, 1000, 800) );//boundingRect());

    contigLayout = new QGraphicsLinearLayout( contigScrollAreaProxy );//this layout manages the contigs
    contigLayout->setOrientation(Qt::Vertical);
    contigScrollAreaProxy->setLayout( contigLayout );



    .......

        Contig* c = new Contig( contigDataPackets[i], sageVisPointer, this, contigScrollAreaProxy); //create contig

        contigLayout->addItem( c );

   ....

  */
